#include "..\tests\tests.h"
#include <time.h>
using namespace std;

// A lot of naive,ugly codes for testing
// Are there any good way...?
// What a lot of labor work!!!

void TestingVector2()
{
	//Vector2 v1(1,2);
	//Vector2 v2(2,3);
	////testing operator;
	//cout<<v1<<'+'<<v2<<'='<<v1+v2<<endl;
	//cout<<v1<<'-'<<v2<<'='<<v1-v2<<endl;
	//cout<<v1<<'*'<<2<<'='<<v1*2<<endl;
	//cout<<v1<<'/'<<2<<'='<<v1/2<<endl;
	//v1 *= 3; v2 /= 3;
	//cout<<v1<<' '<<v2<<endl;
	//v1 -= v2; v2 += v1;
	//cout<<v1<<' '<<v2<<endl;
	////testing vector2 + point2
	//Point2 p(0,1);
	//cout<< v2 <<'+'<<p<<'='<<v2+p<<endl;
	//cout<< p <<'+'<<v1<<'='<<p+v1<<endl;
	////testing normalize
	//Vector2 v3(1,1);
	//v3 = Normalize(v3);
	//cout<<v3<<endl;
	//// testing index
	//cout<<v3[0]<<v3[1]<<endl;
	//cout<<(v3.IsZero()?"Zero":"Not Zero")<<endl;
	//Vector2 v4;
	//Normalize(v4);	// warning
	//cout<<(v4.IsZero()?"Zero":"Not Zero")<<endl;
	//// testing Dot
	//v3 = Vector2(1,1);
	//v4 = Vector2(2,3);
	//cout<<Dot(v3,v4)<<' '<<AbsDot(v3,v4)<<endl;
	//v4 = -v4;
	//cout<<Dot(v3,v4)<<' '<<AbsDot(v3,v4)<<endl;
	//cout<<v3.Length()<<' '<<v3.LengthSqured()<<endl;
	//cout<<"++++++++++++++++++++++++"<<endl;
}
void TestingVector3()
{
	//Vector3 v1(1,2,-1);
	//Vector3 v2(2,3,5);
	////testing operator;
	//cout<<v1<<'+'<<v2<<'='<<v1+v2<<endl;
	//cout<<v1<<'-'<<v2<<'='<<v1-v2<<endl;
	//cout<<v1<<'*'<<2<<'='<<v1*2<<endl;
	//cout<<v1<<'/'<<2<<'='<<v1/2<<endl;
	//v1 *= 3; v2 /= 3;
	//cout<<v1<<' '<<v2<<endl;
	//v1 -= v2; v2 += v1;
	//cout<<v1<<' '<<v2<<endl;
	////testing vector2 + point2
	//Point3 p(0,1,10);
	//cout<< v2 <<'+'<<p<<'='<<v2+p<<endl;
	//cout<< p <<'+'<<v1<<'='<<p+v1<<endl;
	////testing normalize
	//Vector3 v3(1,1,1);
	//v3 = Normalize(v3);
	//cout<<v3<<endl;
	//// testing index
	//cout<<v3[0]<<v3[1]<<v3[2]<<endl;
	//cout<<(v3.IsZero()?"Zero":"Not Zero")<<endl;
	//Vector3 v4;
	//Normalize(v4);	// warning
	//cout<<(v4.IsZero()?"Zero":"Not Zero")<<endl;
	//// testing Dot
	//v3 = Vector3(1,1,2);
	//v4 = Vector3(2,3,-1);
	//cout<<Dot(v3,v4)<<' '<<AbsDot(v3,v4)<<endl;
	//v4 = -v4;
	//cout<<Dot(v3,v4)<<' '<<AbsDot(v3,v4)<<endl;
	//cout<<v3.Length()<<' '<<v3.LengthSqured()<<endl;
	//cout<<"++++++++++++++++++++++++"<<endl;
}
void TestingVector4()
{
	//Vector4 v1(1,2,-1,0);
	//Vector4 v2(2,3,5,1);
	////testing operator;
	//cout<<v1<<'+'<<v2<<'='<<v1+v2<<endl;
	//cout<<v1<<'-'<<v2<<'='<<v1-v2<<endl;
	//cout<<v1<<'*'<<2<<'='<<v1*2<<endl;
	//cout<<v1<<'/'<<2<<'='<<v1/2<<endl;
	//v1 *= 3; v2 /= 3;
	//cout<<v1<<' '<<v2<<endl;
	//v1 -= v2; v2 += v1;
	//cout<<v1<<' '<<v2<<endl;
	////testing normalize
	//Vector4 v3(1,1,1,1);
	//v3 = Normalize(v3);
	//cout<<v3<<endl;
	//// testing index
	//cout<<v3[0]<<v3[1]<<v3[2]<<endl;
	//cout<<(v3.IsZero()?"Zero":"Not Zero")<<endl;
	//Vector4 v4;
	//Normalize(v4);	// warning
	//cout<<(v4.IsZero()?"Zero":"Not Zero")<<endl;
	//// testing Dot
	//v3 = Vector4(1,1,2,1);
	//v4 = Vector4(2,3,-1,1);
	//cout<<Dot(v3,v4)<<' '<<AbsDot(v3,v4)<<endl;
	//v4 = -v4;
	//cout<<Dot(v3,v4)<<' '<<AbsDot(v3,v4)<<endl;
	//cout<<v3.Length()<<' '<<v3.LengthSqured()<<endl;
	//cout<<"++++++++++++++++++++++++"<<endl;
}

void TestingPoint2()
{
	//Point2 p1(1,2);
	//Point2 p2(2,3);
	////testing operator;
	//cout<<p1<<'+'<<p2<<'='<<p1+p2<<endl;	// point2
	//cout<<p1<<'-'<<p2<<'='<<p1-p2<<endl;	// vector2
	//cout<<p1<<'*'<<2<<'='<<p1*2<<endl;		// point2
	//cout<<p1<<'/'<<2<<'='<<p1/2<<endl;		// point2
	//p1 *= 3; p2 /= 3;
	//cout<<p1<<' '<<p2<<endl;			// point2
	//Vector2 v(1,0);
	//p1 -= v; p2 += v;	// point2
	//cout<<p1<<' '<<p2<<endl;
	//testing vector2 + point2
	
}
void TestingPoint3()
{
	//Point3 p;
	//Point3 p1(3,3,4);
	//Vector3 v(1,2,3);
	//cout<<p+v<<endl;
	//cout<<v+p<<endl;
	//cout<<p-v<<endl;
	//cout<<p-p1<<endl;
}

void TestingNormal()
{
	//// testing normal
	//Normal n(1,2,3);
	//n = Normalize(n);
	//Point3 p(1,1,2);
	//cout<<"testing normal\n";
	//cout<<n<<endl;
	//cout<<p+Vector3(n)<<endl;
	//cout<<n+p<<endl;
	//cout<<p+n<<endl;
	//Normal n1(1,2,3);
	//Normal n2(2,4,6);

	//n1 = Normalize(n);
	//cout<<n1<<endl;
	//cout<<n2<<endl;
	////n2.Normalized();
	//cout<<(n1==n2)<<endl;	// 1 - true

	//n2 = -n2;
	//cout<<n2<<endl;

	//Vector3 vv (1,2,3);
	//vv = Normalize(vv);
	//Normal nn(3,1,2);
	//nn = Normalize(nn);
	//cout<<Dot(vv,nn)<<endl;
	//cout<<Dot(nn,vv)<<endl;
	//cout<<Dot(-nn,vv)<<endl;
	//cout<<AbsDot(nn,-vv)<<endl;
	//cout<<Cross(nn,vv)<<endl;
	//cout<<Cross(vv,nn)<<endl;
	//cout<<Cross(nn,nn)<<endl;
	//vv.x = 1; vv.y = 0; vv.z  = 0;
	//Normal nnn(0,1,0);
	//Vector3 s,t;
	//CoordinateSystem(nnn,&s,&t);
	//cout<<vv<<endl;
	//cout<<s<<endl;
	//cout<<t<<endl;
}

void TestingMath() {
	//Point3 p1(1,1,1);
	//Point3 p2(8,10,1);
	//cout<<DistanceSqured(p1,p2)<<endl;
	/*Vector3 x (1,0,0);
	Vector3 y (0,1,0);
	cout<<Cross(x,y)<<endl;*/
}
void TestingRay() {
	//Ray ray(Point3(0,0,0),Vector3(1,2,1));
	//cout<<ray(1.2)<<endl;
	//cout<<ray.ToString()<<endl;
	//RayDifferential raydiff(ray);
	//raydiff.hasDifferentials = true;
	//raydiff.rx = Ray();
	//raydiff.ry = Ray();
	//cout<<raydiff.ToString()<<endl;
	//Ray ray1(Point3(1,1,1),Vector3(1,3,0),ray);
	//ray1.time = 1;
	//cout<<ray1.ToString()<<endl;
}
void TestingMatrix()
{
	/*Matrix4x4 m1;
	Matrix4x4 m2(Vector4(1,1,1,0),Vector4(2,1,5,0),Vector4(3,4,3,0),Vector4(1,3,2,1));
	cout<<m1.ToString()<<endl;
	cout<<m2.ToString()<<endl;
	cout<<m2.Transpose().ToString()<<endl;
	cout<<m2.Inverse().ToString()<<endl;
	cout<<(m2*(m2.Inverse())).ToString()<<endl;
	Inverse(&m2);
	cout<<m2.ToString()<<endl;
	cout<<m2.Column1().ToString()<<endl;
	m2 /= 2;
	cout<<m2.Column1().ToString()<<endl;
	cout<<m2.Inverse().ToString()<<endl;
	Normal n(1,1,1);
	cout<<m2*n<<endl;
	m2*=2;
	cout<<"********Copy Functions************"<<endl;
	cout<<m2.ToString()<<endl;
	Matrix4x4 m3 = m2;
	cout<<m3.ToString()<<endl;
	Matrix4x4 m6(m3);
	cout<<m6.ToString()<<endl;
	cout<<"*********Copy Functions***********"<<endl;
	m6 = m6;
	cout<<m6.ToString()<<endl;
	Point3 p(1,1,1);
	cout<<m2*p<<endl;
	float mat[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16};
	Matrix4x4 m4(mat);
	cout<<m4.ToString()<<endl;
	m2.Set(mat);
	cout<<m4.ToString()<<endl;*/
	
	// testing inverse function
	/*clock_t t1,t2;
	Matrix4x4 m(1,2,3,4,5,6,13,14,15,16,9,7,8,100,1,12);
	t1 = clock();
	for(int i = 0; i < 1000000; i++)
		m.Inverse();
	t2 = clock();
	cout<<t2-t1<<endl;*/
}
void TestingTransform()
{
	/*Matrix4x4 mat;
	Transform t(mat);
	cout<<t.ToString()<<endl;
	Vector4 v4(1,1,1,1);
	cout<<t(v4)<<endl;
	Vector4 v41;
	t(v4,&v41);
	cout<<v41<<endl;
	Vector3 v3(1,1,1);
	cout<<t(v3)<<endl;
	Point3 p(1,1,1);
	cout<<t(p)<<endl;
	Normal n(1,1,1);
	cout<<t(n)<<endl;*/
	
	// Should be Identity Matrix!!
	//Transform lookat = LookAt(Point3(),Point3(0,0,1),Vector3(0,1,0));
	//cout << lookat.ToString() << endl;
	//// Any Matrix
	//Transform lookat2 = LookAt(Point3(),Point3(1,1,1),Vector3(0,1,0));
	//cout<< lookat2.ToString() << endl;
}
void TestingSSE()
{
	// This test seems not quite right..
	// do not know why

	RNG rng;
	Timer timer;
#define NUM   10000000
	if(1) 
	{
		timer.Start();
		Vector4 a = Vector4(rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat());
		Vector4 b = Vector4(rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat());
		Vector4 c;
		for ( int i=0; i < NUM; ++i)
		{
			for(int j = 0; j < 4; j++)
			{
				c[j] += a[j] + b[j];
				c[j] += a[j] - b[j];
				c[j] += a[j] * b[j];
				c[j] += a[j] / b[j];
			}
		}
		timer.Stop();
	} else
	{
		timer.Start();
		__m128 a = _mm_set_ps(rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat());
		__m128 b = _mm_set_ps(rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat(), rng.RandomFloat());
		__m128 c = _mm_setzero_ps();
		for ( int i=0; i < NUM; ++i)
		{
			c = _mm_add_ps(c, _mm_add_ps(a, b));
			c = _mm_add_ps(c, _mm_sub_ps(a, b));
			c = _mm_add_ps(c, _mm_mul_ps(a, b));
			c = _mm_add_ps(c, _mm_div_ps(a, b));
		}
		timer.Stop();
	}

	cout <<timer.Value() << endl;

}

void TestingObjLoader() {

	// four possible layout
	// case 1: f v1			v2			v3
	// case 2: f v1/vt1		v2/vt2		v3/vt3    <--|
	// case 3: f v1//vn1	v2//vn2		v3//vn3   <--|	be careful with these two!
	// case 4: f v1/vt1/vn1	v2/vt2/vn2	v3/vt3/vn3

	//string filename = "model/cornell_box.obj";		// case 1
	//string filename = "model/CornellBoxBalls.obj";	// case 3
	string filename = "model/eagle_tex_12_30.obj";		// case 4
	int nt,nv;
	int *vi = NULL;
	Point3 *P = NULL;
	Normal *N = NULL;
	Point2 *uv = NULL;
	LoadObj(filename, &nt, &nv, vi, P, N, uv);

	std::cout<<"pause";
	/*for(int i = 0 ;i < nv; i++)
		std::cout << vi[i];*/
}

void TestingSampler() {
	//Sampler * sampler = new LDSampler(0,100,0,100,64);
	//Sample *sample = new Sample[64];
	//int n = sampler->GetMoreSamples(sample);
	//std::cout << n <<endl;
}

void RunTesting()
{
	//TestingVector2();
	//TestingVector3();
	//TestingVector4();
	//TestingPoint2();
	//TestingPoint3();
	//TestingNormal();
	//TestingMath();
	//TestingRay();
	//TestingMatrix();
	//TestingTransform();
	//TestingSSE();

	//TestingObjLoader();

	//TestingSampler();
}